import {
  Component,
  OnInit,
  ElementRef,
  ViewChild,
  AfterViewInit,
  TemplateRef,
  HostListener,
} from '@angular/core';
import { Terminal } from 'xterm';
import { Base64 } from 'js-base64';
import { fit } from 'xterm/lib/addons/fit/fit';
import { WebSocketSubject } from 'rxjs/webSocket';
import { ResizeService } from 'app/modules/share/services/resize.service';
import { map, startWith } from 'rxjs/operators';
import { MatDialog } from '@angular/material';
import { FormBuilder, Validators } from '@angular/forms';
import { markAllAsTouched } from 'app/modules/base/helper';
import { ActivatedRoute } from '@angular/router';
import { ToasterService } from 'app/modules/share/services/toaster.service';
import { SshService } from '../services/ssh.service';

@Component({
  selector: 'm-ssh',
  templateUrl: './ssh.component.html',
  styleUrls: ['./ssh.component.scss'],
})
export class SshComponent implements OnInit, AfterViewInit {
  constructor(
    private route: ActivatedRoute,
    private fb: FormBuilder,
    public dialog: MatDialog,
    private resizeService: ResizeService,
    private toaster: ToasterService,
    private sshService: SshService,
  ) {}
  @ViewChild('terminalRef') terminalRef: ElementRef<HTMLDivElement>;
  @ViewChild('loginRef') loginRef: TemplateRef<any>;

  loginForm = this.fb.group({
    username: ['', Validators.required],
    password: ['', Validators.required],
  });

  term = new Terminal();
  resize$ = this.resizeService.$WindowResize.pipe(
    map(() => {
      fit(this.term);
    }),
  );
  init = false;
  ws$: WebSocketSubject<WebSSHMessage>;
  id: number;
  maxAttempNums: number;
  maxTimes: number;
  ngOnInit() {
    // 隐藏横向滚动条
    document.body.style.overflowX = 'hidden';
    this.id = Number(this.route.snapshot.queryParamMap.get('id'));
    this.maxAttempNums = 0;
    this.maxTimes = 10;
    this.connectSsh();
    this.openLogin();
  }
  //链接到ssh
  connectSsh() {
    const url = `ws://${location.host}/api/admin/pc/${this.id}/webssh`;
    this.ws$ = new WebSocketSubject({ url });
    // 发送输入流
    this.term.on('data', (data) =>
      this.ws$.next({ type: WebSSHMessageType.Stdin, data: Base64.encode(data) }),
    );
    // 设置终端大小
    this.term.on('resize', (data) => this.ws$.next({ type: WebSSHMessageType.Resize, ...data }));
    // 接收输出流
    this.ws$.subscribe(
      (msg) => {
        switch (msg.type) {
          case WebSSHMessageType.Stdout:
          case WebSSHMessageType.Stderr:
            // 连接成功后发送心跳
            if (!this.init) {
              this.init = true;
              console.log('first connect');
              //add ping pong
              var that = this;
              setInterval(function () {
                that.ws$.next({
                  type: WebSSHMessageType.Ping,
                  data: Base64.encode(WebSSHMessageType.Ping),
                });
              }, 5 * 1000);
            }
            this.term.write(Base64.decode(msg.data));
        }
      },
      async (err) => {
        console.log('async err');
        console.error(err);
        console.log('his.maxAttempNums', this.maxAttempNums);
        if (++this.maxAttempNums <= this.maxTimes) {
          console.log('relogin,times:', this.maxAttempNums);
          this.connectSsh();
          this.ws$.next({
            type: WebSSHMessageType.Login,
            data: Base64.encode(this.loginForm.value.username),
            msg: Base64.encode(this.loginForm.value.password),
          });
          return false;
        }
        // 连接断开
        this.toaster.warn('连接断开');
        this.term.writeln('\n连接断开');
        this.dialog.closeAll();
      },
    );
  }
  @HostListener('window:beforeunload', ['$event'])
  beforeUnloadHander(event) {
    this.ws$.next({ type: WebSSHMessageType.Logout, data: Base64.encode('logout') });
  }

  // 初始化xterm
  ngAfterViewInit() {
    setTimeout(() => {
      this.term.open(this.terminalRef.nativeElement);
      fit(this.term);
    });
  }
  // 登录对话框
  openLogin() {
    this.dialog.open(this.loginRef, { width: '30rem', disableClose: true });
  }
  async validateLdapUser(id: number, username: string, password: string) {
    let result: ldapValidRs;
    try {
      await this.sshService.validateLdap(id, username, password);
      result = {
        success: true,
        msg: null,
      };
    } catch (err) {
      result = {
        success: false,
        msg: err.error,
      };
    } finally {
      return result;
    }
  }

  // ssh验证登录
  async login() {
    markAllAsTouched(this.loginForm);
    if (this.loginForm.invalid) {
      return;
    }
    const username = this.loginForm.value.username;
    const password = this.loginForm.value.password;
    // 验证ldap用户密码，非ldap用户跳过验证
    //const result = await this.validateLdapUser(this.id, username, password)
    //if (!result.success) {
    //this.toaster.warn(`${result.msg}`);
    //this.term.writeln(`\n${result.msg}`);
    //return false;
    //}
    this.ws$.next({
      type: WebSSHMessageType.Login,
      data: Base64.encode(this.loginForm.value.username),
      msg: Base64.encode(this.loginForm.value.password),
    });

    // this.ws$.next({
    //   type: WebSSHMessageType.Password,
    //   data: Base64.encode(this.loginForm.value.password),
    // });
    this.dialog.closeAll();
    this.term.focus();
  }
}

enum WebSSHMessageType {
  Stdin = 'stdin',
  Stdout = 'stdout',
  Stderr = 'stderr',
  Resize = 'resize',
  Login = 'login',
  Ping = 'ping',
  Password = 'password',
  Logout = 'logout',
}
interface WebSSHMessage {
  type: WebSSHMessageType;
  data?: string;
  msg?: string;
  cols?: number;
  rows?: number;
}
interface ldapValidRs {
  success: boolean;
  msg: string;
}
